package algo3.algothief.modelo;

import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;


public class RutaDeEscape {
	
	private ArrayList<Pais> rutaDeEscape;
	private int cantidadDePaisesIterados;
	
	private int cantidadDePaisesVisitados;
	
//-------------------------------------------------------------------------------------
	
	public RutaDeEscape(Pais paisDondeSeRobo, Mundo mundo, int cantidadDePaisesAVisitar) {
		// El menos uno es porque se tiene que visitar cantidadDePaisesAVisitar 
		// paises menos el primer pais que se visita: el paisDondeSeRobo.
		this.cantidadDePaisesVisitados = (cantidadDePaisesAVisitar - 1);
		
		this.rutaDeEscape = new ArrayList<Pais>();
		rutaDeEscape.add(paisDondeSeRobo);
	
		this.agregarPaisesALaRuta(mundo);
		this.cantidadDePaisesVisitados++;
		
		this.cantidadDePaisesIterados = 0;
	}
	
	private RutaDeEscape(ArrayList<Pais> paisesDeLaRuta, int paisesIterados, int paisesVisitados) {
		this.rutaDeEscape = paisesDeLaRuta;
		this.cantidadDePaisesIterados = paisesIterados;
		this.cantidadDePaisesVisitados = paisesVisitados;
	}
	
//-------------------------------------------------------------------------------------
	
	public Element serializar(Document doc) {
		Element elementoRuta = doc.createElement("RutaDeEscape");
		
		Element elementoPaises = this.serializarPaises(doc);
		
		Element elementoCantidadDePaisesIterados = doc.createElement("CantidadDePaisesIterados"); 
		Element elementoCantidadDePaisesVisitados = doc.createElement("CantidadDePaisesVisitados");
		elementoCantidadDePaisesIterados.setAttribute("cantidad", Integer.toString(cantidadDePaisesIterados));
		elementoCantidadDePaisesVisitados.setAttribute("cantidad", Integer.toString(cantidadDePaisesVisitados));
		
		elementoRuta.appendChild(elementoPaises);
		elementoRuta.appendChild(elementoCantidadDePaisesIterados);
		elementoRuta.appendChild(elementoCantidadDePaisesVisitados);
					
		return elementoRuta;
	}
		
	public static RutaDeEscape hidratar(Document doc, ArrayList<Pais> paisesDelMundo) throws ParserConfigurationException, SAXException, IOException {
		Element elementoRuta = (Element)doc.getElementsByTagName("RutaDeEscape").item(0);
		
		ArrayList<Pais> paisesDeLaRuta = RutaDeEscape.hidratarPaises(elementoRuta, paisesDelMundo);
		
		Element elementoCantidadDePaisesIterados = (Element)elementoRuta.getElementsByTagName("CantidadDePaisesIterados").item(0);
		String cantidadDePaisesIteradosEnFormaDeString = elementoCantidadDePaisesIterados.getAttribute("cantidad");
		int cantidadDePaisesIterados = Integer.parseInt(cantidadDePaisesIteradosEnFormaDeString);
		
		Element elementoCantidadDePaisesVisitados = (Element)elementoRuta.getElementsByTagName("CantidadDePaisesVisitados").item(0);
		String cantidadDePaisesVisitadosEnFormaDeString = elementoCantidadDePaisesVisitados.getAttribute("cantidad");
		int cantidadDePaisesVisitados = Integer.parseInt(cantidadDePaisesVisitadosEnFormaDeString);
		
		RutaDeEscape rutaNueva = new RutaDeEscape(paisesDeLaRuta, cantidadDePaisesIterados, cantidadDePaisesVisitados);
		
		return rutaNueva;
	}
	
//-------------------------------------------------------------------------------------
	
	private Element serializarPaises(Document doc) {
		Integer cantidadDePaises = rutaDeEscape.size();
		
		Element elementoPaises = doc.createElement("PaisesDeLaRuta");
		elementoPaises.setAttribute("cantidadDePaises", cantidadDePaises.toString());
		
		for (Integer i = 1; i < cantidadDePaises + 1; i++) {
			Pais pais = rutaDeEscape.get(i-1);
			
			Element elementoPais = doc.createElement("PaisDeLaRuta" + "-" + i.toString());
			elementoPais.setAttribute("nombreDeLaCapital", pais.verNombreDeLaCapital());
			
			elementoPaises.appendChild(elementoPais);
		}
		
		return elementoPaises;
	}
	
	
	
	private static int buscarIndiceEnPaisesDelPais(ArrayList<Pais> paises, String nombreDelPais) {
		int indiceDelPais = -1;
		int cantidadDePaises = paises.size();
		
		for (int i = 0; ( (indiceDelPais == -1) && (i < cantidadDePaises) ); i++) {
			String nombreDelPaisActual = paises.get(i).verNombreDeLaCapital();
			
			if (nombreDelPaisActual.matches(nombreDelPais)) 
				indiceDelPais = i;
		}
		
		return indiceDelPais;
	}
	
	private static ArrayList<Pais> hidratarPaises(Element elementoRuta, ArrayList<Pais> paises) {
		Element elementoPaises = (Element)elementoRuta.getElementsByTagName("PaisesDeLaRuta").item(0);
		
		ArrayList<Pais> paisesDeLaRuta = new ArrayList<Pais>();
		
		String cantidadDePaisesEnFormaDeString = elementoPaises.getAttribute("cantidadDePaises");
		Integer cantidadDePaises = Integer.parseInt(cantidadDePaisesEnFormaDeString);
		
		for (Integer i = 1; i < cantidadDePaises + 1; i++) {
			Element elementoPais = (Element)elementoPaises.getElementsByTagName("PaisDeLaRuta" + "-" + i.toString()).item(0);
			String nombreDeLaCapital = elementoPais.getAttribute("nombreDeLaCapital");
		
			int indiceDelPaisDelMismoNombre = RutaDeEscape.buscarIndiceEnPaisesDelPais(paises, nombreDeLaCapital);
			Pais paisDeLaRuta = paises.get(indiceDelPaisDelMismoNombre);
			
			paisesDeLaRuta.add(paisDeLaRuta);
		}
		
		return paisesDeLaRuta;
	}
	
	
	
	private void agregarPaisesALaRuta(Mundo mundo) {
		int indiceAnterior = -1;
		
		for (int i = 0; i < cantidadDePaisesVisitados; i++) {
			Pais paisActual = rutaDeEscape.get(i);
			
			ArrayList<Pais> paisesPosibles = mundo.verLosPosiblesPaisesALosQueSePuedeViajar(paisActual);
			
			int cantidadDePaisesPosibles = paisesPosibles.size();
			
			int indiceActual = indiceAnterior;
			while (indiceActual == indiceAnterior)
				indiceActual = (int)( Math.random() * cantidadDePaisesPosibles );
			
			Pais siguientePais =  paisesPosibles.get(indiceActual);
			rutaDeEscape.add(siguientePais);
			
			indiceAnterior = indiceActual;
		}
	}
		
//-------------------------------------------------------------------------------------

	public int verCantidadDePaisesVisitados() {
		return this.cantidadDePaisesVisitados;
	}
	
	public int verCantidadDePaisesIterados() {
		return this.cantidadDePaisesIterados;
	}
	
	public boolean quedanPaisesEnLaRuta() {
		boolean sePuedeSeguirAvanzando = cantidadDePaisesIterados < cantidadDePaisesVisitados;
		return sePuedeSeguirAvanzando;
	}
	
	
	public Pais verElPaisNumero(int indice) {
		return rutaDeEscape.get(indice);
	}
	
	public Pais siguientePaisEnLaRuta() {
		if (this.quedanPaisesEnLaRuta()) {
			int indiceDelProximoPais = this.cantidadDePaisesIterados;
			this.cantidadDePaisesIterados++;
			
			return rutaDeEscape.get(indiceDelProximoPais);
		}
		return null;
	}
}

